﻿using System;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;

namespace DataScripter.Export.Code
{
	public class ObjectExporter<T> : ObjectExporter
		where T : class
	{
		public ObjectExporter(T instance, IExportPropertyValidator exportPropertyValidator)
			: base(instance, typeof(T), exportPropertyValidator)
		{ }
	}

	public class ObjectExporter
	{
		public enum ExportType
		{
			VariableDeclaration,
			PropertyInitialization
		}
		private CodeBuilder _builder;
		public object Instance { get; set; }
		public Type InstanceType { get; set; }
		public IExportPropertyValidator ExportPropertyvalidator { get; set; }

		public ObjectExporter(object instance, Type instanceType, IExportPropertyValidator exportPropertyvalidator)
		{
			Instance = instance;
			InstanceType = instanceType;
			ExportPropertyvalidator = exportPropertyvalidator;
		}

		public string Export(string variableName, ExportType exportType)
		{
			if (Instance == null)
			{
				return InstanceType.Name + " " + variableName + " = null";
			}
			_builder = new CodeBuilder();

			if (exportType == ExportType.VariableDeclaration)
			{
				_builder.AppendLine(InstanceType.Name + " " + variableName + " = new " + InstanceType.Name);
			}
			else
			{
				_builder.AppendLine(variableName + " = new " + InstanceType.Name);
			}
			_builder.AppendLine("{");

			_builder.Indentation += 2;
			PropertyInfo[] properties = InstanceType.GetProperties();
			foreach (PropertyInfo propertyInfo in properties)
			{
				ExportProperty(propertyInfo);
			}
			_builder.Indentation -= 2;


			if (exportType == ExportType.VariableDeclaration)
				_builder.AppendLine("}");
			else
			{
				_builder.Append("}");
			}
			return _builder.ToString();
		}

		private void ExportProperty(PropertyInfo propertyInfo)
		{
			if (propertyInfo.GetCustomAttributes(false)
				.OfType<XmlIgnoreAttribute>()
				.Count() > 0)
				return;

			if (!propertyInfo.CanRead)
				return;

			if (!ExportPropertyvalidator.ValidatePropertyCanBeExported(propertyInfo))
				return;

			object property = propertyInfo.GetValue(Instance, null);
			bool isValue = propertyInfo.PropertyType.IsValueType || (propertyInfo.PropertyType.Equals(typeof(string)) && property != null);
			if (isValue )
			{
				_builder.AppendLine("{0} = {1},", propertyInfo.Name, CSharp.ToCSharp(property));
			}
			else
			{
				if (property != null)
				{
					ObjectExporter exporter = new ObjectExporter(property, propertyInfo.PropertyType, ExportPropertyvalidator);
					string code = exporter.Export(propertyInfo.Name, ExportType.PropertyInitialization);
					_builder.AppendLines(code + ",");
				}
			}
		}
	}
}
